﻿using System;
using System.Data;
using Complaint.Models.Dtos;
using Complaint.Repositories;
using NUnit.Framework;
using Rhino.Mocks;

namespace Complaint.Models.Test
{
    [TestFixture]
    public class CategoryModelTest
    {
        private string _title1, _title2, _title3;
        private MockRepository _mocks;
        private CategoryRepository _repository;
        private CategoryModel _model;

        [TestFixtureSetUp]
        public void SetUp()
        {
            _title1 = Guid.NewGuid().ToString();
            _title2 = Guid.NewGuid().ToString();
            _title3 = Guid.NewGuid().ToString();
            _mocks = new MockRepository();
            _repository = _mocks.StrictMock<CategoryRepository>();
            _model = new CategoryModel() { Repository = _repository };
        }

        [TestFixtureTearDown]
        public void CleanUp()
        {
            _title1 = null;
            _title2 = null;
            _title3 = null;
            _mocks = null;
            _repository = null;
            _model = null;
        }

        [Test]
        [Description("Asserts the correct repository methods are called.")]
        public void ShouldCallCreate()
        {
            var category = new Category { Title = _title1, Status = true };
            using (_mocks.Record())
            {
                Expect.Call(() => _repository.Create(category));
            }

            using (_mocks.Playback())
            {
                _model.Create(category);
            }
        }

        [Test]
        public void ShouldCreateTestCategory()
        {
            using (new UnitOfWorkScope(true))
            {
                var model = new CategoryModel();
                var category = new Category { Title = _title1, Status = true };

                int countBefore = model.Retrieve().Count;
                model.Create(category);
                int countAfter = model.Retrieve().Count;

                Assert.That(countBefore == countAfter - 1);

                var c = model.FindById(category.CategoryID);
                Assert.That(c, Is.EqualTo(category));
            }
        }

        [Test]
        public void ShouldRetrieveByName()
        {
            using (new UnitOfWorkScope(true))
            {
                var model = new CategoryModel();
                var category = new Category { Title = _title2, Status = true };

                model.Create(category);

                var c = model.FindByName(_title2);
                Assert.That(c.Count == 1);
            }
        }

        [Test]
        public void ShouldUpdate()
        {
            using (new UnitOfWorkScope(true))
            {
                var model = new CategoryModel();
                var p = model.FindByName(_title1)[0];
                var c = model.FindByName(_title2)[0];
                c.Title = _title3;
                c.Parent = p;

                model.Update(c);

                var child = model.FindById(c.CategoryID);
                Assert.That(c.Title, Is.Not.EqualTo(_title2));
                Assert.That(c.Title, Is.EqualTo(_title3));
                Assert.That(child.Parent, Is.EqualTo(p));
            }
        }

        [Test]
        public void ShouldRetrieveByCategory()
        {
            using (new UnitOfWorkScope(true))
            {
                var model = new CategoryModel();
                var child = model.FindByName(_title3)[0];
                var parent = model.FindByName(_title1)[0];

                var c = model.FindByCategory(parent.CategoryID);
                Assert.That(c.Count == 1);
                Assert.That(c[0], Is.EqualTo(child));
            }
        }

        [Test, ExpectedException(typeof(UpdateException))]
        public void ShouldFailCascadeDeleteTestCategory()
        {
            using (new UnitOfWorkScope(true))
            {
                var model = new CategoryModel();
                var category = model.FindByName(_title1)[0];

                model.Delete(category);
            }
        }

        [Test]
        public void ShouldDeleteTestCategoryLeafToRoot()
        {
            using (new UnitOfWorkScope(true))
            {
                var model = new CategoryModel();
                var child = model.FindByName(_title3)[0];
                var parent = model.FindByName(_title1)[0];

                model.Delete(child);
                model.Delete(parent);

                var c = model.FindByName(_title3);
                var p = model.FindByName(_title1);

                Assert.That(c.Count == 0);
                Assert.That(p.Count == 0);
            }
        }

    }
}
